/*
 * pcicfg - PCI drivers & tools for accessing memory location, I/O ports and configuration space.
 * Copyright (C) 2013  Andrew Karasyov
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "pcidevicemanager.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


int main( int argc, char *argv[] )
{
	// Creates PCI device manager instance.
	const char* dev_name = "/dev/" PCICFG_MODNAME;
	PCIDeviceManager device_manager( dev_name );
	bool is_success = device_manager.ReadAllDevices();

	// Checks if device manager successfully established connection to pcicfg driver.
	if ( !is_success || !device_manager.IsGood() )
	{
		std::cout << "Device manager initialization failed.\n";
		exit( EXIT_FAILURE );
	}

	// If no options
	if (argc == 1)
		device_manager.PrintHelp();


	// Checks for BDF mask. It should be first.
	PCIDeviceManager::BDFMask bdf_mask;
	memset( &bdf_mask, 0, sizeof(bdf_mask) );
	if ( (argc > 1) && (argv[1][0] != '-') )
	{
		if( !PCIDeviceManager::BuildBDFMask( argv[1], bdf_mask ) )
		{
			std::cout << "Bulding BDF mask failed." << std::endl;
			exit( EXIT_FAILURE );
		}
	}


	// Determine command line switched
	int c;
	while( -1 != ( c = getopt( argc, argv, "ltx::s:r:") ) )
	{
		switch( c )
		{
		case 'l':
			device_manager.PrintDeviceList( bdf_mask );
			break;

		case 't':
			device_manager.PrintDeviceTree();
			break;

		case 'x':
		{
			unsigned int req_cfg_size = optarg ? strtol (optarg, NULL, 0) : 0;
			device_manager.PrintAllDeviceCfgSpace( req_cfg_size, bdf_mask );
		}
		break;

		case 's':
		{
			PCIDeviceManager::SAssignment assign;
			bool is_ok = PCIDeviceManager::BuildAssignment( optarg, assign );
			if ( !is_ok )
			{
				std::cout << "Building assignment failed." << std::endl;
				exit( EXIT_FAILURE );
			}

			device_manager.AssignRegisterOnDevices( bdf_mask, assign );
		}
		break;

		case 'r':
		{
			PCIDeviceManager::SRegister reg;
			bool is_ok = PCIDeviceManager::BuildRegister( optarg, reg );
			if ( !is_ok )
			{
				std::cout << "Building register failed." << std::endl;
				exit( EXIT_FAILURE );
			}

			device_manager.ReadRegisterOnDevices( bdf_mask, reg );
		}
		break;

		default:
			device_manager.PrintHelp();
			exit( EXIT_SUCCESS );
			break;
		}
	}


	return EXIT_SUCCESS;
}
